#ifndef VA_ADB_H
#define VA_ADB_H

#include "addon.h"
#include "adb_msg_win.h"
#include "adb_msg_manage.h"
#include <list>
#include <thread>

namespace VA
{
    class Adb : public Nan::ObjectWrap
    {
    public:
        static NAN_MODULE_INIT(Init)
        {
            auto className = Nan::New("Adb").ToLocalChecked();
            auto tpl = Nan::New<v8::FunctionTemplate>(New);
            tpl->SetClassName(className);
            auto instance_tpl = tpl->InstanceTemplate();
            instance_tpl->SetInternalFieldCount(1);

            CUSTOM_NAN_HANDLE_ACCESSOR(instance_tpl, index);
            CUSTOM_NAN_SET_PROTOTYPE_METHOD(tpl, Test);
            CUSTOM_NAN_SET_PROTOTYPE_METHOD(tpl, shell);

            Nan::SetPrototypeMethod(tpl, "getShell", NewInstance);
            constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
            Nan::Set(target, className, Nan::GetFunction(tpl).ToLocalChecked());
        }

        static NAN_METHOD(NewInstance)
        {
            const int argc = 1;
            int value = info[0]->IsNumber() ? Nan::To<int>(info[0]).FromJust() : 0;
            v8::Local<v8::Value> argv[1] = { Nan::New(value) };
            auto cons = Nan::New(constructor());
            info.GetReturnValue().Set(Nan::NewInstance(cons, argc, argv).ToLocalChecked());
        }

    private:
        explicit Adb(int value = 0);
        ~Adb();

        static void DisposeAll(void* data) {
            auto runtime = static_cast<Adb*>(data);
            delete runtime;
        }

        static NAN_METHOD(New)
        {
            if (info.IsConstructCall())
            {
                int value = info[0]->IsUndefined() ? 0 : Nan::To<int>(info[0]).FromJust();
                auto obj = new Adb(value);
#if NODE_VERSION_AT_LEAST(11, 0, 0)
                node::AddEnvironmentCleanupHook(info.GetIsolate(), DisposeAll, obj);
#else                                                                   
                node::AtExit(DisposeAll, obj);
#endif
                obj->Wrap(info.This());
                info.GetReturnValue().Set(info.This());
            }
            else
            {
                const int argc = 1;
                v8::Local<v8::Value> argv[argc] = { info[0] };
                auto cons = Nan::New(constructor());
                info.GetReturnValue().Set(Nan::NewInstance(cons, argc, argv).ToLocalChecked());
            }
        }

        static inline Nan::Persistent<v8::Function>& constructor()
        {
            static Nan::Persistent<v8::Function> my_constructor;
            return my_constructor;
        }

    public:
        CUSTOM_NAN_METHOD(Adb, shell)
        CUSTOM_NAN_METHOD(Adb, Test)

    public:
        CUSTOM_NAN_GETTERR_HEADER(Adb, index)

    private:
        int _index;
        std::shared_ptr<AdbMsgManage> mAdbMsgManage;

    };

}

#endif